#ifndef __OMODEL_H__
#define __OMODEL_H__

class oModel;
class oActionInterval;
class oSequence;
class oSpriteDef;
class oModelDef;

typedef delegate<void (oModel* model, uint32 index)> oAnimationHandler;

/** @brief A look is to change visibility of a model`s different parts.
 For example you can change a character`s face by different look.
 It`s component class of oModel. Do not use it alone.
*/
class oLook
{
public:
	enum {None = -1};
	void add(CCNode* node);
	void apply();
	void unApply();
private:
	vector<CCNode*> _nodes;
};

/** @brief It`s component class of oModelDef. Do not use it alone. */
class oAnimation
{
public:
	enum {None = -1};
	oAnimation(CCNode* node, oSequence* action);
	~oAnimation();
	void run();
	void pause();
	void resume();
	void stop();
	void setTime(ccTime time);
	ccTime getTime() const;
	ccTime getDuration() const;
	void setSpeed(float speed);
	float getSpeed() const;
	CCNode* getNode() const;
	oSequence* getAction();
private:
	CCNode* _node;
	oSequence* _action;
};

class oResetAnimation: public CCObject
{
public:
	void add(CCNode* node, CCFiniteTimeAction* action);
	void run(ccTime duration);
	void stop();
	delegate<void()> end;
private:
	void onActionEnd();
	struct oAnimationPair
	{
		oAnimationPair(CCNode* node, CCFiniteTimeAction* action);
		~oAnimationPair();
		CCNode* node;
		CCFiniteTimeAction* action;
	};
	ptr_vector<oAnimationPair> _group;
};

class oDLL oModel: public CCSpriteBatchNode
{
public:
	oModel(oModelDef* def);
	virtual ~oModel();
	PROPERTY_NAME(int, Look);
	PROPERTY(float, _speed, Speed);
	PROPERTY(bool, _loop, Loop);
	PROPERTY_NAME(ccTime, Time);
	PROPERTY_READONLY(ccTime, Duration);
	PROPERTY(float, _recoverTime, Recovery);
	void setLook(const string& name);
	void play(uint32 index);
	void play(const string& name);
	void pause();
	void resume();
	void resume(uint32 index);
	void resume(const string& name);
	void stop();
	bool isPlaying() const;
	bool isPaused() const;
	int getCurrentAnimationIndex() const;
	oModelDef* getModelDef() const;
	void onResetAnimationEnd();
	oAnimationHandler animationEnd;
	static oModel* none();
private:
	void addLook(uint32 index, CCNode* node);
	void addAnimation(uint32 index, CCNode* node, oSequence* action);
	void reset(oSpriteDef* parentDef, CCNode* parentNode);
	void onActionEnd();
	bool _isPlaying;
	bool _isPaused;
	bool _isRecovering;
	int _currentLook;
	int _currentAnimation;
	oModelDef* _pModelDef;
	ptr_vector<oLook> _looks;
	ptr_vector< ptr_vector<oAnimation> > _animationGroups;
	oResetAnimation _resetAnimation;
	friend class oModelDef;
};

#endif